其他
牛逼!Android11 最全适配实践指北来啦
The following article is from 码上积木 Author 积木zz
前言
Android11
的到来,到时候迎接我的就是客户的指责,甚至老板的一封休书了 😂。Android11
到底改了些什么,以及最重要的,我们需要怎么适配?targetversion不改到30,是不是就不用适配了呢?以 Android11
为目标版本的应用(targetSdkVersion>=30
才有影响)⭐所有应用在 Android11
设备上适配改动(无论targetSdkVersion是多少,只要在Android11设备
上运行的应用都有影响)
targetSdkVersion>=30
的模块呢?因为一般来说为了Google为了让我们更长时间适应新的内容以及保障线上应用的稳定,都会把改动大的,需要花时间适配的内容放到新的targetSdkVersion
对应的应用上,如果你暂时没有适配targetSdkVersion30
的需求,也可以看看第二模块,看看是否有涉及你的应用相关内容。GOGOGO!Android11
发布进度调整,欢迎点赞关注。(打⭐的格外注意哦)适配targetSdkVersion30
targetSdkVersion 30
或者以上才生效。分区存储强制执行⭐
“ 对外部存储目录的访问仅限于应用专属目录,以及应用已创建的特定类型的媒体。 ”
Android10
就已经推行了,简单的说,就是应用对于文件的读写只能在沙盒环境,也就是属于自己应用的目录里面读写。其他媒体文件可以通过MediaStore
进行访问。targetSdkVersion = 29
应用中,设置android:requestLegacyExternalStorage="true"
,就可以不启动分区存储,让以前的文件读取正常使用。但是targetSdkVersion = 30
中不行了,强制开启分区存储。当然,作为人性化的android,还是为开发者留了一小手,如果是覆盖安装呢,可以增加
android:preserveLegacyExternalStorage="true"
,暂时关闭分区存储,好让开发者完成数据迁移的工作。为什么是暂时呢?因为只要卸载重装
,就会失效了。以下是关于分区存储会遇到的所有情况,给大家罗列出来了,先上代码:if (checkPermission()) {
//getExternalStoragePublicDirectory被弃用,分区存储开启后就不允许访问了
val filePath = Environment.getExternalStoragePublicDirectory("").toString() + "/test3.txt"
val fw = FileWriter(filePath)
fw.write("hello world")
fw.close()
showToast("文件写入成功")
}
}
1)
targetSdkVersion = 28
,运行后正常读写。2)
targetSdkVersion = 29
,不删除应用,targetSdkVersion 由28修改到29,覆盖安装,运行后正常读写。3)
targetSdkVersion = 29
,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))4)
targetSdkVersion = 29
,添加android:requestLegacyExternalStorage="true"(不启用分区存储),读写正常不报错5)
targetSdkVersion = 30
,不删除应用,targetSdkVersion 由29修改到30,读写报错,程序崩溃(open failed: EACCES (Permission denied))6)
targetSdkVersion = 30
,不删除应用,targetSdkVersion 由29修改到30,增加android:preserveLegacyExternalStorage="true",读写正常不报错7)
targetSdkVersion = 30
,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))val file = File(context.filesDir, filename)
//应用专属外部存储空间
val appSpecificExternalDir = File(context.getExternalFilesDir(), filename)
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
println("image uri is $uri")
}
cursor.close()
}
SAF(存储访问框架--Storage Access Framework)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, 100)
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == 100) {
val uri = data.data
println("image uri is $uri")
}
}
访问应用专属文件
Android 10适配要点,作用域存储
AndroidQ(10)分区存储完美适配
调用 ACTION_MANAGE_STORAGE intent
操作检查可用空间。调用 ACTION_CLEAR_APP_CACHE intent
操作清除所有缓存。
就来不及了
。媒体文件访问权限 ⭐
“ 为了在保证用户隐私的同时可以更轻松地访问媒体,Android 11 增加了以下功能。执行批量操作和使用直接文件路径和原生库访问文件。 ”
MediaStore API
中添加了多种方法,用于简化特定媒体文件更改流程(例如在原位置编辑照片),分别是:createWriteRequest()
用户向应用授予对指定媒体文件组的写入访问权限的请求。createFavoriteRequest()
用户将设备上指定的媒体文件标记为“收藏”的请求。对该文件具有读取访问权限的任何应用都可以看到用户已将该文件标记为“收藏”。createTrashRequest()
用户将指定的媒体文件放入设备垃圾箱的请求。垃圾箱中的内容会在系统定义的时间段后被永久删除。createDeleteRequest()
用户立即永久删除指定的媒体文件(而不是先将其放入垃圾箱)的请求。
val editPendingIntent = MediaStore.createWriteRequest(contentResolver,
urisToModify)
// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
null, 0, 0, 0)
override fun onActivityResult(requestCode: Int, resultCode: Int,
data: Intent?) {
when (requestCode) {
EDIT_REQUEST_CODE ->
if (resultCode == Activity.RESULT_OK) {
/* Edit request granted; proceed. */
} else {
/* Edit request not granted; explain to the user. */
}
}
}
直接文件路径
访问访问媒体文件!哈哈,这样就方便多了。也就是除了 MediaStore API
之外还有两种方式可以访问媒体文件:File API。 原生库,例如 fopen()。
Android10
咋办呢??要不就用MediaStore
,要不就直接把分区存储关了吧(requestLegacyExternalStorage=true)所有文件访问权限 ⭐
MANAGE_EXTERNAL_STORAGE
这不来了吗。这个权限就是用来获取所有文件
的管理权限。🌰:val intent = Intent()
intent.action= Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivity(intent)
//判断是否获取MANAGE_EXTERNAL_STORAGE权限:
val isHasStoragePermission= Environment.isExternalStorageManager()
电话号码相关权限 ⭐
“ Android 11 更改了您的应用在读取电话号码时使用的与电话相关的权限。 ”
TelecomManager 类中的 getLine1Number()
方法TelecomManager 类中的 getMsisdn()
方法
READ_PHONE_STATE
权限不管用了,需要READ_PHONE_NUMBERS
权限才行。targetSdkVersion
修改到30,然后运行一个获取电话号码的程序:ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE), 100)
btn2.setOnClickListener {
val tm = this.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val phoneNumber = tm.line1Number
showToast(phoneNumber)
}
java.lang.SecurityException: getLine1NumberForDisplay: Neither user 10151 nor current process has android.permission.READ_PHONE_STATE, android.permission.READ_SMS, or android.permission.READ_PHONE_NUMBERS
Andmanifest.xml
中注册好权限,并且添加动态权限申请:<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_PHONE_NUMBERS), 100)
READ_PHONE_NUMBERS
这一个权限:<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
自定义消息框视图被屏蔽 ⭐
“ 从 Android 11 开始,已弃用自定义消息框视图。如果您的应用以 Android 11 为目标平台,包含自定义视图的消息框在从后台发布时会被屏蔽 ”
自定义消息框视图
啊?我说英文你就知道了,英文是custom toast views
,也就是自定义toast。简单写个代码:toast.setDuration(show_length);
toast.setView(view);
toast.show();
IToast.show("你好,我是自定义toast")
}, 3000)
W/NotificationService: Blocking custom toast from package com.example.studynote due to package not in the foreground
现在需要 APK 签名方案 v2 ⭐
“ 对于以 Android 11(API 级别 30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用 APK 签名方案 v2 或更高版本进行签名。用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。 ”
targetSdkVersion
修改到30,那么你就必须要加上v2签名才行。否则无法安装和更新。媒体intent操作需要系统默认相机 ⭐
android.media.action.IMAGE_CAPTURE
android.media.action.IMAGE_CAPTURE_SECURE
intent
唤起照相机,使用VIDEO_CAPTURE
的action,只有系统的相机能够响应,而第三方的相机应用不会响应了。intent.action=android.provider.MediaStore.ACTION_IMAGE_CAPTURE
startActivity(intent)
//无法唤起第三方相机了,只能唤起系统相机
intent
设置软件包名称或组件来使这些intent变得明确。5G ⭐
“ Android 11 添加了在您的应用中支持 5G 的功能 ”
5G相关的
一些功能,包括:检测是否连接到了5G网络 检查按流量计费性
TelephonyManager
的监听方法:val tManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
tManager.listen(object : PhoneStateListener() {
@RequiresApi(Build.VERSION_CODES.R)
override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
if (ActivityCompat.checkSelfPermission(this@Android11Test2Activity, android.Manifest.permission.READ_PHONE_STATE) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
return
}
super.onDisplayInfoChanged(telephonyDisplayInfo)
when(telephonyDisplayInfo.networkType) {
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> showToast("高级专业版 LTE (5Ge)")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> showToast("NR (5G) - 5G Sub-6 网络")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> showToast("5G+/5G UW - 5G mmWave 网络")
else -> showToast("other")
}
}
}, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
}
流量计费
的,否则5G的流量可不是开玩笑的。manager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
//true 代表连接不按流量计费
val isNotFlowPay=networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) ||
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
}
})
如果为 true
,则将连接视为不按流量计费。后台位置信息访问权限 ⭐
“ 在搭载 Android 11 的设备上,当应用中的某项功能请求在后台访问位置信息时,用户看到的系统对话框不再包含用于启用后台位置信息访问权限的按钮。如需启用后台位置信息访问权限,用户必须在设置页面上针对应用的位置权限设置一律允许选项。 ”
从Android10系统的设备开始,就需要请求后台位置权限 (ACCESS_BACKGROUND_LOCATION)
,并选择Allow all the time (始终允许)
才能获得后台位置权限。Android11设备上再次加强
对后台权限的管理,主要表现在系统对话框
上,对话框不再提示始终允许字样,而是提供了位置权限的设置入口,需要在设置页面选择始终允许
才能获得后台位置权限。在搭载 Android11系统
的设备上,targetVersion小于11的时候,可以前台后台位置权限一起申请,并且对话框提供了文字说明,表示需要随时获取用户位置信息,进入设置选择始终允许
即可。但是targetVersion为30的时候,你必须单独申请
后台位置权限,而且要在获取前台权限之后,顺序不能乱
。并且无任何提示,需要开发者自己设计提示样式。
Android10设备
,申请前台和后台位置权限(任意targetSdkVersion):Android11设备
,targetSdkVersion<=29(Android 10),申请前台和后台位置权限:Android11设备
,targetSdkVersion=30(Android 11),申请前台和后台位置权限:Android11设备
,targetSdkVersion=30(Android 11),先申请前台位置权限,后申请后台位置权限:targetSdkVersion<30
情况下,如果你之前就有判断过前台和后台位置权限,那就无需担心,没有什么需要适配。targetSdkVersion>30
情况下,需要分开申请前后台位置权限,并且对后台位置权限申请做好说明和引导,当然也是为了更好的服务用户。
.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (permissionAccessCoarseLocationApproved) {
val backgroundLocationPermissionApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (backgroundLocationPermissionApproved) {
//前后台位置权限都有
} else {
//申请后台权限
if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R){
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
200)
}else{
AlertDialog.Builder(this).setMessage("需要提供后台位置权限,请在设置页面选择始终允许")
.setPositiveButton("确定", DialogInterface.OnClickListener { dialog, which ->
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
200)
}).create().show()
}
}
} else {
if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R){
//申请前台和后台位置权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION),
100)
}else{
//申请前台位置权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
100)
}
}
软件包可见性 ⭐
“ Android 11 更改了应用查询用户已在设备上安装的其他应用以及与之交互的方式。使用新的 元素,应用可以定义一组自身可访问的其他应用。通过告知系统应向您的应用显示哪些其他应用,此元素有助于鼓励最小权限原则。此外,此元素还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。 ”
Android11中
,如果你想去获取其他应用的信息,比如包名,名称等等,不能直接获取了,必须在清单文件中添加<queries>
元素,告知系统你要获取哪些应用信息或者哪一类应用。val listAppcations: List<ApplicationInfo> = pm
.getInstalledApplications(PackageManager.GET_META_DATA)
for (app in listAppcations) {
Log.e("lz",app.packageName)
}
Android11
版本,只能查询到自己应用和系统应用的信息,查不到其他应用的信息了。怎么呢?添加<queries>
元素,两种方式:<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
</manifest>
intent
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
</manifest>
浏览器或者设备管理器
咋办呢?我就要获取所有包名啊?放心,Android11还引入了 QUERY_ALL_PACKAGES
权限,清单文件中加入即可。但是Google Play
可不一定能滥用哦,它为需要QUERY_ALL_PACKAGES 权限的应用会提供相关指南,但是还没出来,具体要看后面的消息了。文档访问限制
“ 为让开发者有时间进行测试,以下与存储访问框架 (SAF) 相关的变更只有在应用以 Android 11 为目标平台时才会生效。 ”
SAF(存储访问框架--Storage Access Framework)
来访问公共目录,但是Android11再次升级,部分目录和文件不能访问了,具体如下:ACTION_OPEN_DOCUMENT_TREE intent
操作请求访问以下目录:内部存储卷的根目录。 设备制造商认为可靠的各个 SD 卡卷的根目录,无论该卡是模拟卡还是可移除的卡。可靠的卷是指应用在大多数情况下可以成功访问的卷。 Download 目录。
ACTION_OPEN_DOCUMENT_TREE
或 ACTION_OPEN_DOCUMENT intent
操作请求用户从以下目录中选择单独的文件:Android/data/ 目录及其所有子目录。 Android/obb/ 目录及其所有子目录。
限制对 APN 数据库的读取访问
“ 以 Android 11 为目标平台的应用现在必须具备 Manifest.permission.WRITE_APN_SETTINGS 特权,才能读取或访问电话提供程序 APN 数据库。如果在不具备此权限的情况下尝试访问 APN 数据库,会生成安全异常。 ”
指一种网络接入技术,是通过手机上网时必须配置的一个参数,APN配置参数包括名字,运营商编号,APN接入点等等。
Manifest.permission.WRITE_APN_SETTINGS
权限就不能读取APN数据库了,但是!这个权限很早之前就被限定只有系统程序才能申请这个权限了,现在这个特权没理解到是什么意思,难道系统程序都不能随便申请了?有大神
可以评论区留言告知。在元数据文件中声明“无障碍”按钮使用情况
“ 从 Android 11 开始,您的无障碍服务无法在运行时声明与系统的“无障碍”按钮的关联。如果您将 AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON 附加到 AccessibilityServiceInfo 对象的 flags 属性,框架就不会将“无障碍”按钮回调事件传递给您的服务。 ”
AccessibilityServiceInfo
要设置flag为FLAG_REQUEST_ACCESSIBILITY_BUTTON,getAccessibilityButtonController
方法获取辅助功能按钮控制器,并且可用于查询辅助功能按钮的状态并注册监听器以进行交互和辅助功能按钮的状态更改。flagRequestAccessibilityButton
标记声明您的无障碍服务与“无障碍”按钮的关联。Firebase JobDispatcher 和 GCMNetworkManager
“ 如果您的应用以 API 级别 30 或更高级别为目标平台,在搭载 Android 6.0(API 级别 23)或更高版本的设备上会停用 Firebase JobDispatcher 和 GcmNetworkManager API 调用。 ”
WorkManager
,这个国内是可以用的,属于jetpack组件,主要用于调度和执行可延期的后台工作。设备到设备文件传输
“ 如果您的应用以 Android 11 为目标平台,您将无法再使用 allowBackup 属性停用应用文件的设备到设备迁移。系统会自动启用此功能。不过,即使您的应用以 Android 11 为目标平台,您也可以通过将 allowBackup 属性设置为 false 来停用应用文件的云端备份和恢复。 ”
代表是否允许应用参与备份和恢复基础架构。如果将此属性设为 false,则永远不会为该应用执行 备份或恢复
,即使是采用全系统备份方法也不例外(这种备份方法通常会通过 adb 保存所有应用数据)。此属性的默认值为 true。
设备到设备
迁移,但是可以停用云端备份和恢复
自动重置权限
“ 如果应用以 Android 11 为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。此操作与用户在系统设置中查看权限并将应用的访问权限级别更改为拒绝的做法效果一样。如果应用已遵循有关在运行时请求权限的最佳做法,那么您不必对应用进行任何更改。这是因为,当用户与应用中的功能互动时,您应该会验证相关功能是否具有所需权限。 ”
每次需要调用权限
的时候都会去判断,那么就不会有什么问题。Settings.ACTION_APPLICATION_DETAILS_SETTINGS action
的 Intent将用户定向到系统设置中应用的页面。isAutoRevokeWhitelisted()
方法。如果此方法返回 true,代表系统不会自动重置应用的权限。前台服务类型
“ 从 Android 9 开始,应用仅限于在前台访问摄像头和麦克风。为了进一步保护用户,Android 11 更改了前台服务访问摄像头和麦克风相关数据的方式。如果您的应用以 Android 11 为目标平台并且在某项前台服务中访问这些类型的数据,您需要在该前台服务的声明的 foregroundServiceType 属性中添加新的 camera 和 microphone 类型。 ”
位置信息、摄像头和麦克风
,那么就这样添加:<service ...
android:foregroundServiceType="location|camera|microphone" />
</manifest>
适配Android11手机
Android11
手机上存在的改动,与targetSdkVersion
无关。数据访问审核 ⭐
“ 为了让应用及其依赖项访问用户私密数据的过程更加透明,Android 11 引入了数据访问审核功能。借助此流程得出的见解,您可以更好地识别和纠正可能出现的意外数据访问。 ”
AppOpsManager.OnOpNotedCallback
。无论是应用本身,还是依赖库或者SDK中的代码,只要访问到私密数据(危险权限),都会回调给我们。透明规范
,否则对于私有数据的使用和管理并不全面和方便。而且还可以对权限使用添加归因
,也就是一个tag,标志权限用到了什么地方。方便回调的时候知晓哪里使用了私有数据
。override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test1)
//创建归因(attribute)
attributionContext = createAttributionContext("shareLocation")
//监听事件
val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {
private fun logPrivateDataAccess(
opCode: String, attributionTag: String, trace: String) {
Log.i(TAG, "Private data accessed. " +
"Operation: $opCode\n " +
"Attribution Tag:$attributionTag\nStack Trace:\n$trace")
}
override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {
syncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(syncNotedAppOp.op,
it,
Throwable().stackTrace.toString())
}
}
override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {
syncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(syncNotedAppOp.op,
it,
Throwable().stackTrace.toString())
}
}
override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
asyncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(asyncNotedAppOp.op,
it,
asyncNotedAppOp.message)
}
}
}
//开启私密数据监听
val appOpsManager =
getSystemService(AppOpsManager::class.java) as AppOpsManager
appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback)
btn1.setOnClickListener {
getLocation()
}
}
fun getLocation() {
val locationManager = attributionContext.getSystemService(
LocationManager::class.java) as LocationManager
if (!checkPermission()) {
return
}
val location: Location? = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
if (location != null) {
showToast("${location.latitude}")
}
}
获取位置信息
的功能,如果调用到getLocation
方法,就会触发onNoted
回调,回调信息包括危险权限code以及归因。onNoted
正常情况下都会回调到该方法onAsyncNoted
如果数据访问并非发生在应用调用API期间,就会调用onAsyncNoted(),比如一些监听器的回调。onSelfNoted
在极少数情况下,如果应用将自身的UID传递到 noteOp(),需要调用 onSelfNoted()。
Attribution Tag:shareLocation
Stack Trace:
[Ljava.lang.StackTraceElement;@14f5a16
android:coarse_location
以及归因 shareLocation
单次授权
“ 在 Android 11 中,每当应用请求与位置信息、麦克风或摄像头相关的权限时,面向用户的权限对话框会包含仅限这一次选项。如果用户在对话框中选择此选项,系统会向应用授予临时的单次授权。 ”
位置信息、麦克风或摄像头
相关的权限时,系统会自动提供一个单次授权
的选项,只供这一次权限获取。然后用户下次打开app的时候,系统会再次提示用户授予权限。这个影响应该不大,只要我们每次使用的时候都去判断权限,没有就去申请即可。放一张新版本权限获取样式:权限对话框的可见性
“ Android 11 建议不要请求用户已选择拒绝的权限。在应用安装到设备上后,如果用户在使用过程中屡次针对某项特定的权限点按拒绝,此操作表示其希望“不再询问”。 ”
良好建议
。建议在用户多次拒绝之后,不要再展示权限申请。Scudo Hardened Allocator
“ Android 11 在内部使用 Scudo Hardened Allocator 为堆分配提供服务。Scudo 能够检测并减轻某些类型的内存安全违规行为。如果您在原生代码崩溃报告中发现与 Scudo 相关的崩溃(例如 Scudo ERROR:),请参阅 Scudo 问题排查文档。 ”
Scudo
是一种动态的用户模式内存分配器,旨在抵御与堆相关的漏洞,同时保持良好的性能。它是一个开源的项目。Android 11中,将采用这个新的heap分配器
,性能更好,更安全。文件描述符排错程序
“ Android 10 引入了 fdsan(文件描述符排错程序)。fdsan 检测错误处理文件描述符所有权的错误,例如 use-after-close 和 double-close。在 Android 11 中,fdsan 的默认模式发生了变化。现在,fdsan 会在检测到错误时中止,而以前的行为则是记录警告并继续。 ”
fdsan
是啥?先要了解fd是啥Unix/Linux
系统文件操作的相关概念,它在形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。系统的进程也就是使用了这个fd
来标示打开的文件,有了它就能对文件做各种操作,获得文件的各种相关信息了。fdsan
也就是检测文件处理中发生的一些错误。应用使用情况统计信息
“ 为了更好地保护用户,Android 11 将每个用户的应用使用情况统计信息存储在凭据加密存储空间中。 ”
UsageStatsManager
,UsageStatsManager
是Android提供统计应用使用情况的服务。通过这个服务可以获取指定时间区间内应用使用统计数据、组件状态变化事件统计数据以及硬件配置信息统计数据。queryAndAggregateUsageStats
方法,可以获取指定时间区间内使用统计数据,以应用包名为键值进行数据合并。isUserUnlocked()
方法返回true的时候,才能正常访问这些数据。也就是以下两种情况:用户在系统启动后首次解锁其设备 用户在设备上切换到自己的帐号
JobScheduler API 调用限制调试
JobScheduler
任务调度器,可以在设备空闲时做一些任务处理。Android11中如果你设置为debug模式
(debuggable 清单属性设置为 true),超出速率限制的JobScheduler API
调用将返回 RESULT_FAILURE
。这个有什么用呢?应该可以帮助我们发现一些性能问题,感兴趣的可以自己试试。WorkManager
也是用到了JobScheduler,不熟悉的同学可以去了解下,JobScheduler
是由SystemServer进程启动的一个系统服务,所以才可以有这么大的权限。无障碍操作
“ 在以前的 Android 版本中,框架会向未正确处理基于点击的无障碍操作的微件分派触摸事件。通常,这些视图会直接处理触摸事件,而不是注册点击监听器。为了在正确定义无障碍操作的应用中创建更一致的行为,Android 11 绝不会分派触摸事件。相反,系统会完全依赖于基于点击的无障碍操作:ACTION_CLICK 和 ACTION_LONG_CLICK。此更改会影响屏幕阅读器的行为。 ”
Android
手机上有个预安装的屏幕阅读服务,叫做TalkBack
,为视力障碍人士或者视力状态不佳的老年人提供。那我们应用为了让这个阅读器能够读懂你的自定义view操作,必须给与自定义控件定义处理程序,包括点击,长按
等操作。原来版本可能对于OnTouchListener
也支持无障碍触摸事件,而在Android11
中,必须专门制定点击或者长按事件才行了。给个🌰:// 0, 1, or 2.
var currentState: Int = 0
private set
init {
updateAccessibilityActions()
}
private fun updateAccessibilityActions() {
ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
action-label) {
view, args -> moveToNextState()
})
}
private fun moveToNextState() {
currentState = (currentState + 1) % 3
}
}
TriSwitch
,继承自Switch,由于和Switch
的点击效果不一样,所以必须通过替换 ViewCompat.replaceAccessibilityAction()
来重新定义相应的无障碍操作。非SDK接口限制
“ Android 11 包含更新后的受限制非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保提供公开替代方案。 ”
总结
targetSdkVersion=30
的内容中,这也是每次Android发版的一个潜规则吧,为了最大程度不影响已上线的app所作出的举动。但是,这并不意味我们就可以不改。因为应用可拖不起,用户可拖不起,毕竟升级才能给到用户
最好的体验
。而且各大应用市场也都会建议或者强制应用升级targetSdkVersion
,以便适配最新的手机。推荐阅读
• Android Studio 4.1重磅发布:支持内嵌安卓模拟器!
推荐一个UP主
皇叔刘望舒,著有三本技术畅销书,蝉联三届电子工业出版社年度优秀作者。谷歌开发者社区 、Droidcon等技术大会特邀讲师,CSDN 2018年度十大博客之星。前华为面试官,现大厂技术负责人,11年经验的大厂技术专家。
皇叔入驻B站,除了分享技术,还会聊一些“过来人”的经验,欢迎提前关注。
最近面试BAT,整理一份面试资料《大厂Java面试通关指北》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 BAT 领取,更多内容陆续奉上。如有收获,点个在看,诚挚感谢 明天见(。・ω・。)ノ♡
• Android Studio 4.1重磅发布:支持内嵌安卓模拟器!
推荐一个UP主
皇叔刘望舒,著有三本技术畅销书,蝉联三届电子工业出版社年度优秀作者。谷歌开发者社区 、Droidcon等技术大会特邀讲师,CSDN 2018年度十大博客之星。前华为面试官,现大厂技术负责人,11年经验的大厂技术专家。
皇叔入驻B站,除了分享技术,还会聊一些“过来人”的经验,欢迎提前关注。
最近面试BAT,整理一份面试资料《大厂Java面试通关指北》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 BAT 领取,更多内容陆续奉上。如有收获,点个在看,诚挚感谢